#pragma once
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <websocketpp/server.hpp>
#include <websocketpp/config/asio_no_tls.hpp>
#include "logger.hpp"

namespace im_server {

typedef websocketpp::server<websocketpp::config::asio> WsServer;

class Connection
{
    struct Client 
    {
        Client(const std::string& uid, const std::string& ssid)
            : userId(uid), sessionId(ssid) {}
        std::string userId;
        std::string sessionId;
    };
public:
    Connection() {}
    ~Connection() {}

    void insert(const WsServer::connection_ptr& conn, const std::string& uid, const std::string& sessionId)
    {
        std::lock_guard<std::mutex> locker(mtx_);
        userIdConnections_.emplace(uid, conn);
        ConnectionClient_.emplace(conn, Client(uid, sessionId));
        LOG_ERROR("与客户端{}-{}建立长连接成功!", uid, sessionId);
    }
    WsServer::connection_ptr getConnection(const std::string& uid)
    {
        std::lock_guard<std::mutex> locker(mtx_);
        auto it = userIdConnections_.find(uid);
        if(it == userIdConnections_.end()) {
            LOG_ERROR("客户端信息({})对应的长连接没有建立!", uid);
            return WsServer::connection_ptr();;
        }
        return it->second;
    }
    bool getClient(const WsServer::connection_ptr& conn, std::string& userId, std::string& sessionId)
    {
        std::lock_guard<std::mutex> locker(mtx_);
        auto it = ConnectionClient_.find(conn);
        if(it == ConnectionClient_.end()) {
            LOG_ERROR("长连接对应的客户端信息不存在!");
            return false;
        }
        userId = it->second.userId;
        sessionId = it->second.sessionId;
        return true;
    }
    bool remove(const WsServer::connection_ptr& conn) 
    {
        std::lock_guard<std::mutex> locker(mtx_);
        auto it = ConnectionClient_.find(conn);
        if(it == ConnectionClient_.end()) {
            LOG_ERROR("长连接对应的客户端信息不存在! 无法移除连接映射的客户端信息");
            return false;
        }
        userIdConnections_.erase(it->second.userId);
        ConnectionClient_.erase(conn);
        return true;
    }
private:
    std::mutex mtx_;
    std::unordered_map<std::string, WsServer::connection_ptr> userIdConnections_;
    std::unordered_map<WsServer::connection_ptr, Client> ConnectionClient_;
};

using ConnectionPtr = std::shared_ptr<Connection>;

}
